home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 18011 < prev    next >
Encoding:
Text File  |  1996-08-05  |  3.4 KB  |  122 lines

  1. Path: news.th-darmstadt.de!news
  2. From: Enno Sandner <enno@intellektik.informatik.th-darmstadt.de>
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: Here is my idea of callback code. However there are glitches can it be done better.
  5. Date: Thu, 18 Apr 1996 15:56:34 +0200
  6. Organization: Fachbereich Informatik, TH Darmstadt
  7. Message-ID: <31764A12.1CFBAE39@intellektik.informatik.th-darmstadt.de>
  8. References: <Pine.SUN.3.91N2x.960418124921.4515B-100000@mumrik.nada.kth.se>
  9. NNTP-Posting-Host: kitz.intellektik.informatik.th-darmstadt.de
  10. Mime-Version: 1.0
  11. Content-Type: text/plain; charset=iso-8859-1
  12. Content-Transfer-Encoding: 8bit
  13. X-Mailer: Mozilla 2.01 (X11; I; SunOS 4.1.3 sun4m)
  14.  
  15. Fredrik ╓hrstr÷m wrote:
  16. > How do people write callbacks? The following code captures what I want
  17. > of callbacks.
  18. > * Callbacks call class functions.
  19. > * The calling object does not need to know what object, what function,
  20. >   what callback it is calling. It knows that it calls a TutCallback f.ex.
  21. >   but if the user wants to subclass the TutCallback to insert more
  22. >   information at callback time thats completely ok.
  23. > * It is easy to create new callbacks. (Before I hade to create two classes
  24. >   for each new callback.)
  25. > However there are some negative things.
  26. > * It is a pointer to pointer to function thingi.
  27. > * The compiler warns >>Contravariance violation<<
  28. >   Because I cast b = void (Test::*)(TutCallback*)
  29. >                   to void (Test::*)(Callback*)
  30. >   And I do not know how to stop this from happening.
  31. >   Is there anyone out there that has a better way of calling callbacks?
  32. >   Or if somebody knows how to fix this I would be very happy!
  33. > Here's the code. (Just the essential stuff, no memchecking and so on.)
  34. > #include <iostream.h>
  35. > struct Caller;
  36. > template<class T> struct Call;
  37. > struct Callback;
  38. > struct Caller
  39. > {
  40. >   virtual void call (Callback *cb) { }
  41. > };
  42. > template<class T>
  43. > struct Call : public Caller
  44. > {
  45. >   typedef void (T::*FuncPtr)(Callback *);
  46. >   Call (T *o, FuncPtr f) : object_(o), function_(FuncPtr(f)) { }
  47. >   void call (Callback *cb) { (object_->*function_) (cb); }
  48. >   T *object_;
  49. >   FuncPtr function_;
  50. > };
  51. > struct Callback
  52. > {
  53. >   Callback (Caller *caller) : caller_ (caller) { }
  54. >   virtual void invoke () { caller_->call (this); }
  55. >   Caller *caller_;
  56. > };
  57. > // This is an easy way to create new Callbacks I think!
  58. > struct TutCallback : public Callback
  59. > {
  60. >   TutCallback (Caller *c, int u) : Callback (c), tut (u) { }
  61. >   int tut;
  62. > };
  63. > struct Test
  64. > {
  65. >   TutCallback *cb;
  66. >   Test ()
  67. >   {
  68. >     cb = new TutCallback (new Call<Test>(this,b), 5);
  69. >     cb->invoke ();
  70. >   }
  71. >   void b (TutCallback *cb)
  72. >   {
  73. >     cerr << "Tut! " << cb->tut << endl;
  74. >   }
  75. > };
  76. > int main ()
  77. > {
  78. >   Test test;
  79. > }
  80.  
  81. Basically your idea is ok (check out the 'Command Pattern' in the Design
  82. Patterns book for a more general approach).
  83. To remove the problems you can make 'Caller' a generic class that takes
  84. the type of the argument of the 'call' function:
  85.  
  86.        template<class Arg> class Caller {
  87.           public:
  88.           virtual ~Caller() {}    
  89.           virtual void call(Arg a)=0;
  90.        };
  91.  
  92. The resulting subclass 'Call' becomes generic with two arguments.
  93.      
  94.        template<class T,class Arg> class Call : public Caller<Arg> { ... };
  95.  
  96. This and the appropriate modifications allows you to write:
  97.  
  98.     cb = new TutCallback (new Call<Test,TutCallback*>(this,b), 5);
  99.  
  100. in Test's constructor without any problems.
  101.  
  102.     Enno
  103.